#pragma once
#include<strings.h>
#include<iostream>
#include<string>
#include<sstream>
#include<vector>
#include<functional>
#include<fstream>
#include<unordered_map>

static const std::string base_sep="\r\n";
static const std::string line_sep=": ";
static const std::string prefixe_path="wwwroot";
static const std::string homepage="index.html";
static const std::string http_version="HTTP/1.0";
static const std::string spacesep=" ";
static const std::string suffixsep=".";
static const std::string arg_sep="?";





class HttpRequest
{
private:
    std::string GetLine(std::string &reqstr)
    {
        auto pos=reqstr.find(base_sep);
        if(pos==std::string::npos)return std::string();
        std::string line=reqstr.substr(0,pos);

        reqstr.erase(0,line.size()+base_sep.size());
        return line.empty()?base_sep:line;
    }
        
    void ParseHeader()
    {
        std::stringstream ss(_req_line);
        ss>>_method>>_url>>_version;
        if(strcasecmp(_method.c_str(),"GET")==0)
        {
            auto pos=_url.find(arg_sep);
            if(pos!=std::string::npos)
            {
                _body_text=_url.substr(pos+arg_sep.size());//也可以新创建一个成员存放
                _url.resize(pos);
            }
        }
        _path+=_url;
        if(_path[_path.size()-1]=='/')
        {
            _path+=homepage;
        }

        auto pos=_path.rfind(suffixsep);
        if(pos!=std::string::npos)
        {
            _suffix=_path.substr(pos);
        }
        else
        {
            _suffix=".default";
        }
    }
        
    void ParseReqHeaders()
    {
        for(auto & header:_req_headers)
        {
            auto pos=header.find(line_sep);
            if(pos==std::string::npos)continue;
            std::string k=header.substr(0,pos);
            std::string v=header.substr(pos+line_sep.size());
            if(k.empty() || v.empty())continue;
            _headers_ky.insert(std::make_pair(k,v));
        }
    }
public:
    HttpRequest():_blank_line(base_sep),_path(prefixe_path)
    {}
    void DeSerialize(std::string &reqstr)
    {
        _req_line=GetLine(reqstr);
        std::string header;
        while(true)
        {
            header=GetLine(reqstr);
            if(header.empty())break;
            if(header==base_sep)break;
            _req_headers.push_back(header);
        }
        if(!reqstr.empty())
        {
            _body_text=reqstr;
        }
        ParseHeader();
        ParseReqHeaders();
    }
    std::string Path()
    {
        LOG(INFO,"path:%s\n",_path.c_str());
        return _path;
    }
    std::string Suffix()
    {
        return _suffix;
    }
    std::string GetRequestBody()
    {
        LOG(INFO,"bodytext:%s\n",_body_text.c_str());
        return _body_text;
    }
    std::string GetMethod()
    {
        LOG(INFO,"method:%s\n",_method.c_str());
        return _method;
    }
    void Printf()
    {
        std::cout<<"----------------------------------------------"<<std::endl;

        std::cout<<"@@@"<<_req_line<<std::endl;
        for(auto header:_req_headers)
        {
            std::cout<<"###"<<header<<std::endl;
        }
        std::cout<<"$$$"<<_blank_line<<std::endl;
        std::cout<<">>>"<<_body_text<<std::endl;
        std::cout<<"********************************************"<<std::endl;
        std::cout<<_method<<std::endl;
        std::cout<<_url<<std::endl;
        std::cout<<_version<<std::endl;
        for(auto &hread:_headers_ky)
        {
            std::cout<<hread.first<<")))"<<hread.second<<std::endl;
        }

    }
    ~HttpRequest()
    {}
private:
    std::string _req_line;
    std::vector<std::string> _req_headers;
    std::string _blank_line;
    std::string _body_text;

    //具体字段
    std::string _method;
    std::string _url;
    std::string _path;
    std::string _suffix;//请求的资源的后缀
    std::string _version;
    std::unordered_map<std::string,std::string> _headers_ky;
};

class HttpResponse
{
public:
    HttpResponse():_blank_line(base_sep),_version(http_version)
    {}
    void AddCode(int code,const std::string &desc)
    {
        _status_code=code;
        _desc=desc;
    }
    void AddHeader(std::string k,std::string v)
    {
        _headers_kv[k]=v;
    }
    void AddBodyText(const std::string &textstr)
    {
        _resp_body_text=textstr;
    }
    std::string Serialize()
    {
        //构建序列化前期工作
        _status_line=_version+spacesep+std::to_string(_status_code)+spacesep+_desc+base_sep;
        for(auto &header:_headers_kv)
        {
            std::string head=header.first+line_sep+header.second+base_sep;
            _resp_headers.push_back(head);
        }

        //正式序列化
        std::string responsestr;
        responsestr=_status_line;
        for(auto &line:_resp_headers)
        {
            responsestr+=line;
        }
        responsestr+=_blank_line;
        responsestr+=_resp_body_text;
        return responsestr;
    }
    ~HttpResponse()
    {}
private:
    //应答基本属性
    std::string _version;
    int _status_code;
    std::string _desc;
    std::unordered_map<std::string,std::string> _headers_kv;

    //应答基本格式
    std::string _status_line;
    std::vector<std::string> _resp_headers;
    std::string _blank_line;
    std::string _resp_body_text;

    
};

using func_t=std::function<HttpResponse(HttpRequest&)>;

class HttpServer
{
private:
    std::string GetFileText(const std::string &path)
    {
        std::ifstream in(path,std::ios::binary);
        if(!in.is_open())return std::string();
        in.seekg(0,in.end);
        int n=in.tellg();
        in.seekg(0,in.beg);

        std::string content;
        content.resize(n);
        in.read((char*)content.c_str(),n);
        in.close();
        return content;
    }
public:
    HttpServer()
    {
        _mime_type.insert(std::make_pair(".jpg","image/jepg"));
        _mime_type.insert(std::make_pair(".html","text/html"));
        _mime_type.insert(std::make_pair(".default","text/html"));

        _code_to_desc.insert(std::make_pair(404,"Not Found"));
        _code_to_desc.insert(std::make_pair(200,"OK"));
        _code_to_desc.insert(std::make_pair(301,"Moved Permanently"));
        _code_to_desc.insert(std::make_pair(302,"Found"));




    }
    std::string HandlerHttpRequest(std::string &reqstr)
    {
#ifdef TEST
        std::cout<<"------------------------------------------------"<<std::endl;

        std::cout<<req<<std::endl;
        return "";
#else
        HttpRequest req;
        req.DeSerialize(reqstr);
        // req.Printf();

        std::string path=req.Path();
        req.GetMethod();
        req.GetRequestBody();
        HttpResponse resp;

        if(path=="wwwroot/redir")
        {
            std::string redir_path="https://www.qq.com";
            resp.AddCode(302,_code_to_desc[302]);
            resp.AddHeader("Location",redir_path);
        }
        else if(!req.GetRequestBody().empty())
        {
            if(IsServiceExists(req.Path()))
            {
                resp=_service_list[req.Path()](req);
            }
        }
        else
        {
            std::string content=GetFileText(path);
            if(content.empty())
            {
                content=GetFileText("wwwroot/404.html");

                resp.AddCode(404,_code_to_desc[404]);
                resp.AddBodyText(content);
                resp.AddHeader("Content-Length",std::to_string(content.size()));
                resp.AddHeader("Content-Type",_mime_type[".html"]);

            }
            else
            {
                resp.AddCode(200,_code_to_desc[200]);
                resp.AddBodyText(content);
                resp.AddHeader("Content-Length",std::to_string(content.size()));
                resp.AddHeader("Content-Type",_mime_type[req.Suffix()]);
            }
        }


        return resp.Serialize();
#endif
    }
    void InsertService(const std::string &servicename,func_t f)
    {
        std::string s=prefixe_path+servicename;
        _service_list[s]=f;
    }
    bool IsServiceExists(const std::string &servicename)
    {
        auto iter=_service_list.find(servicename);
        if(iter==_service_list.end())return false;
        return true;
    }
    ~HttpServer()
    {}
private:
    std::unordered_map<std::string,std::string> _mime_type;
    std::unordered_map<int,std::string> _code_to_desc;
    std::unordered_map<std::string,func_t> _service_list;
};
